<?php

namespace app\push\controller;

use think\Db;
use Workerman\Lib\Timer;
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
use think\Cache;
use think\Session;

class Workerman
{
    protected $HEARTBEAT_TIME = '10';
    
    public function sirenData()
    {
        $index_data = getCheckIndexData();
        
        $news_data = getNewData(2);
        
        $live_video_data = getLiveVideoData();
        $live_music_data = getLiveMusicData();
        
        $siren_data = getSirenData();
        
        $data = [
            'index_data' => json_decode($index_data, true),
            'web_news_list' => $news_data['web_list'],
            'app_news_list' => $news_data['app_list'],
            'web_all_news_count' => $news_data['web_all_news_count'],
            'app_all_news_count' => $news_data['app_all_news_count'],
            'web_today_news_count' => $news_data['web_today_news_count'],
            'app_today_news_count' => $news_data['app_today_news_count'],
            'web_error_count' => $news_data['web_error_count'],
            'app_error_count' => $news_data['app_error_count'],
            'live_video_data' => $live_video_data,
            'live_music_data' => $live_music_data,
            'siren_data' => $siren_data
        ];
        
        return $data;
    }
    
    public function countCrontabErrList()
    {
        // 排序
        $order_sql = Db::name('crontab_log')->order('id desc')->buildSql();
        // 分组
        $group_sql = Db::table($order_sql . ' a')->order('id desc')->group('type,course_id')->buildSql();
        
        $list = Db::table($group_sql . ' b')->where(['status' => 0])->order('id desc')->group('type,course_id')->select();
        
        $pop_ids = file_get_contents(RUNTIME_PATH . 'pop.log');
        $ids = implode(',', array_column($list, 'id'));
        
        $is_pop = false;
        if ($pop_ids != $ids) {
            $pop_ids_arr = explode(',', $pop_ids);
            $ids_arr = explode(',', $ids);
            if (count($pop_ids_arr) < count($ids_arr)) {
                $is_pop = true;
                file_put_contents(RUNTIME_PATH . 'pop.log', $ids);
            } elseif (count($pop_ids_arr) == count($ids_arr)) {
                sort($pop_ids_arr);
                sort($ids_arr);
                if ($pop_ids_arr != $ids_arr) {
                    $is_pop = true;
                    file_put_contents(RUNTIME_PATH . 'pop.log', $ids);
                }
            }
        }
        
        return $is_pop;
    }
    
    public function __construct()
    {
        global $worker;
        // 创建一个Worker监听2346端口，使用websocket协议通讯
        $worker = new Worker("websocket://0.0.0.0:2346");
        
        // 设置时区，避免运行结果与预期不一致
        date_default_timezone_set('PRC');
        
        // 启动1个进程对外提供服务
        $worker->count = 1;
        
        // 新增加一个属性，用来保存uid到connection的映射(uid是用户id或者客户端唯一标识)
        $worker->uidConnections = [];
        
        $worker->onConnect = function ($connection) {
            $msg = [
                'type' => 'admin_connect',
                'msg' => '建立通信成功'
            ];
            $connection->send(json_encode($msg, JSON_UNESCAPED_UNICODE));
        };
        
        $worker->onMessage = function (TcpConnection $connection, $data) {
            $data = json_decode($data, true);
            
            $connection->lastMessageTime = time();
            global $worker;
    
            if($data['type'] == 'user_connect'){
                if (!isset($connection->uid)) {
                    // $data['user_id'] 来自于客户端发送过来的数据，可以来自于数据库，比如此处的user_id就是数据库中的用户id
                    $connection->uid = $data['user_id'];
        
                    /**
                     * 保存uid到connection的映射，这样可以方便的通过uid查找connection，
                     * 实现针对特定uid推送数据
                     **/
                    $worker->uidConnections[$connection->uid] = $connection;
                }
            }
            
            $this->sendMessage($connection, $data);
        };
        
        $worker->onWorkerStart = function ($connection) {
            Timer::add(
                $this->HEARTBEAT_TIME, function () use ($connection) {
                $time_now = time();
                foreach ($connection->connections as $connection) {
                    // 有可能该connection还没收到过消息，则lastMessageTime设置为当前时间
                    if (empty($connection->lastMessageTime)) {
                        $connection->lastMessageTime = $time_now;
                        continue;
                    }
                    
                    $connection->lastMessageTime = $time_now;
                    
                    $sirenData = $this->sirenData();
                    $msg = [
                        'type' => 'siren_data',
                        'data' => $sirenData
                    ];
                    $connection->send(json_encode($msg, JSON_UNESCAPED_UNICODE));
                    $pop_msg = [
                        'type' => 'pop',
                        'data' => $this->countCrontabErrList()
                    ];
                    $connection->send(json_encode($pop_msg, JSON_UNESCAPED_UNICODE));
                }
            }
            );
        };
        
        $worker->onClose = function ($connection) {
//            echo "onClose \n";
        };
        
        $worker->onError = function ($connection, $code, $msg) {
            echo "error $code $msg\n";
        };
        
        worker::runAll();
    }
    
    public function sendMessage($connection, $data)
    {
        global $worker;
    
        $msg_data = [
            'type' => 'update_auth'
        ];
        
        switch ($data['type']) {
        case 'update_auth';
            $user_ids = explode(',', $data['user_ids']);
            
            if($user_ids){
                foreach($user_ids as &$v){
                    if(!empty($worker->uidConnections[$v])){
                        $worker->uidConnections[$v]->send(json_encode($msg_data, JSON_UNESCAPED_UNICODE));
                    }
                }
            }
            break;
        }
    }
}
